package com.cman777.springc.encode.advice;

import com.cman777.springc.common.bean.response.BaseResponse;
import com.cman777.springc.encode.annotation.Encoding;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.Optional;

/**
 * @author chenzhicong
 * @time 2020/4/15 11:32
 * @description
 */
@Slf4j
public abstract class AResponseAdvice implements ResponseBodyAdvice {


    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class aClass, ServerHttpRequest request, ServerHttpResponse serverHttpResponse) {
        boolean encode = false;
        boolean paramFit = false;
        boolean jsonResult = false;

        // 获取注解配置是否解密字段
        Encoding apiEncode = returnType.getMethodAnnotation(Encoding.class);
        // 出参是否需要加密
        encode = Optional.ofNullable(apiEncode).map(a -> a.encrypt()).orElse(true);
        // 出参是否符合规范
        if (body instanceof BaseResponse) {
            paramFit = true;
        }
        // 是否是json响应
        if (selectedContentType.includes(MediaType.APPLICATION_JSON)) {
            jsonResult = true;
        }
        String plainBody = getPlaintext(body);
        //打印返回json
        if (jsonResult) {
            log.info(plainBody);
        }
        if (encode && paramFit && jsonResult && needEncryptOtherCondition()) {
            return encryptStringAndRetObj(plainBody,request);
        } else {
            return body;
        }
    }
    /**
      * 明文
      */
    public abstract String  getPlaintext(Object rtObject);
    /**
      * 解密的附加条件
      */
    public abstract boolean needEncryptOtherCondition();

    /**
      * 对响应Str进行加密并返回一个对象，mvc将使用objectMapper对对象进行序列化在返回给前端
      */
    public abstract Object encryptStringAndRetObj(String bodyStr,ServerHttpRequest request);

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }
}
